package com.gzhryc.net_marketing.cloud.account;

import com.gzhryc.common.event.AbsDelayHandler;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.MultiDBTools;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;

import java.net.URI;
import java.net.URISyntaxException;

/**
 * 回调延迟处理
 * 
 * @author zhanghao 2020-6-26 创建
 */
public class HttpCallbackDelayHandler extends AbsDelayHandler<HttpCallbackDelayEvent> {

	final static Logger log = Logger.getLogger(HttpCallbackDelayHandler.class);

	CloseableHttpAsyncClient client;

	public HttpCallbackDelayHandler() {
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000) // 连接超时,连接建立时间,三次握手完成时间
				.setSocketTimeout(130000) 			// 请求超时,数据传输过程中数据包之间间隔的最大时间
				.setConnectionRequestTimeout(70000) // 使用连接池来管理连接,从连接池获取连接的超时时间
				.build();
		// 配置IO线程
		IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setIoThreadCount(Runtime.getRuntime().availableProcessors()).setSoKeepAlive(true).build();
		// 设置连接池大小
		ConnectingIOReactor ioReactor = null;
		try {
			ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
		} catch (IOReactorException e) {
			e.printStackTrace();
		}
		PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(ioReactor);
		connManager.setMaxTotal(1400);				// 整个连接池的最大连接数
		connManager.setDefaultMaxPerRoute(700);		// 各route默认的最大连接数

		client = HttpAsyncClients.custom().setConnectionManager(connManager).setDefaultRequestConfig(requestConfig).build();
		client.start();
	}

	@Override
	public  boolean execute(final HttpCallbackDelayEvent event) {
		MultiDBTools.setJdbcKey(event.getJdbcKey());
		try {
			String url = event.getUrl();
			if (StringUtils.isNotBlank(url)) {
				String json = event.getStringEntity();
				if(StringUtils.isNotBlank(json)) {
					StringEntity strEntity = new StringEntity(json, ContentType.create("application/json", Consts.UTF_8));
					try {
						URI uri = new URIBuilder(url).build();
						HttpPost httpPost = new HttpPost(uri);
						httpPost.setEntity(strEntity);
						// 请求头信息中添加关闭连接
						httpPost.addHeader("Connection", "close");
						
						client.execute(httpPost, new FutureCallback<HttpResponse>() {
							@Override
							public void completed(HttpResponse result) {
								MultiDBTools.setJdbcKey(event.getJdbcKey());
								try {
									event.sendSuccess(result);
								}finally {
									MultiDBTools.removeJdbcKey();
								}
							}
		
							@Override
							public void failed(Exception ex) {
								log.error("回调响应错误，内容：" + json, ex);
								MultiDBTools.setJdbcKey(event.getJdbcKey());
								try {
									event.sendFail();
								}finally {
									MultiDBTools.removeJdbcKey();
								}
							}
		
							@Override
							public void cancelled() {
								log.error("回调响应取消，内容：" + json);
								MultiDBTools.setJdbcKey(event.getJdbcKey());
								try {
									event.sendFail();
								}finally {
									MultiDBTools.removeJdbcKey();
								}
							}
						});
					} catch (URISyntaxException e) {
						log.error("HTTP回调处理错误", e);
						event.sendFail();
					}
				}else{
					log.error("未找到回调内容，回调事件：{{0:json}}",event);
				}
			}else {
				log.error("未找到回调路径，回调事件：{{0:json}}",event);
			}
		}finally {
			MultiDBTools.removeJdbcKey();
		}
		return true;
	}

}
